Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for the Haskell programming language #2178

Draft
wants to merge 50 commits into
base: main
Choose a base branch
from

Conversation

wenkokke
Copy link

@wenkokke wenkokke commented Jan 17, 2024

Adds support for the Haskell programming language.

Roadmap

  • argumentOrParameter:
  • anonymousFunction
  • branch
    • branch.match
    • branch.match.iteration
    • branch.if
    • branch.if.iteration
    • branch.guard
    • branch.guard.iteration
    • branch.ternary
  • collectionItem
  • collectionKey
    • key.mapPair
    • key.mapPair.iteration
  • comment
    • comment.line
    • comment.block
  • functionCall
    • functionCall
    • functionCall.constructor
  • functionCallee
    • functionCallee
    • functionCallee.constructor
  • functionName
  • ifStatement
  • list
  • map
  • name
    • name.assignment
    • name.assignment.pattern
    • name.function
    • name.class
    • name.field
  • namedFunction
    • namedFunction
    • namedFunction.method
  • statement
    • statement
    • statement.iteration.document
    • statement.iteration.block
  • string
  • type
    • class
    • class.instance
    • className
    • type.adt
    • type.alias
    • type.annotation
    • type.constraint
    • type.dataFamily
    • type.dataInstance
    • type.field
    • type.foreignExport
    • type.foreignImport
    • type.function
    • type.gadt
    • type.newtype
    • type.typeFamily
    • type.typeInstance
  • value
    • value.assignment
    • value.field
    • value.mapPair
    • value.mapPair.iteration
    • value.return
  • condition
    • condition.if
    • condition.ternary
    • condition.match

Warning

This is work in progress. In the early stages, I'll be messy.

  • The commits will be uninformative.
  • The branch may receive force pushes at any point!

Discussion and RFCs

See #2186.


Haskell Node Types

  • adt
  • all_names
  • alt
  • alts
  • annotated_type_variable
  • bind_pattern
  • calling_convention
  • char
  • class
  • class_body
  • class_head
  • class_name
  • comma
  • comment
  • con_list
  • con_tuple
  • con_unit
  • constraint
  • constructor
  • constructor_operator
  • constructors
  • context
  • cpp
  • data_constructor
  • data_constructor_infix
  • data_constructor_record
  • data_family
  • data_instance
  • decl_tyfam_sig
  • decl_type
  • decls
  • default_declaration
  • default_signature
  • deriving
  • deriving_declaration
  • deriving_strategy
  • do_module
  • empty_file
  • equation
  • exp_apply
  • exp_arithmetic_sequence
  • exp_case
  • exp_cond
  • exp_do
  • exp_field
  • exp_if_guard
  • exp_in
  • exp_infix
  • exp_lambda
  • exp_lambda_case
  • exp_let
  • exp_let_in
  • exp_list
  • exp_list_comprehension
  • exp_literal
  • exp_name
  • exp_negation
  • exp_parens
  • exp_record
  • exp_section_left
  • exp_section_right
  • exp_sum_empty
  • exp_th_quoted_name
  • exp_tuple
  • exp_type_application
  • exp_unboxed_sum
  • exp_unboxed_tuple
  • expent
  • export
  • export_names
  • exports
  • field
  • fixity
  • float
  • forall
  • foreign_export
  • foreign_import
  • fun
  • function
  • fundep
  • fundeps
  • gadt_constructor
  • gdpat
  • guard
  • guard_equation
  • guards
  • haskell
  • head
  • impent
  • implicit_param
  • implicit_parid
  • import
  • import_con_names
  • import_item
  • import_list
  • import_package
  • infix
  • inst_datainst
  • inst_tyinst
  • instance
  • instance_head
  • integer
  • label
  • let
  • modifier
  • module
  • namespace
  • newtype
  • newtype_constructor
  • operator
  • pat_apply
  • pat_as
  • pat_field
  • pat_fields
  • pat_infix
  • pat_irrefutable
  • pat_list
  • pat_literal
  • pat_name
  • pat_negation
  • pat_parens
  • pat_record
  • pat_strict
  • pat_tuple
  • pat_typed
  • pat_unboxed_tuple
  • pat_view
  • pat_wildcard
  • pattern
  • pattern_guard
  • pattern_synonym
  • patterns
  • pragma
  • promoted
  • qual
  • qualified_constructor
  • qualified_constructor_operator
  • qualified_module
  • qualified_operator
  • qualified_type
  • qualified_type_operator
  • qualified_variable
  • quantifiers
  • quasiquote
  • quasiquote_bar
  • quasiquote_body
  • quasiquote_start
  • quoter
  • rec
  • record_fields
  • role_annotation
  • safety
  • signature
  • splice
  • stmt
  • strict_type
  • string
  • ticked
  • top_splice
  • transform
  • tycon_arrow
  • type
  • type_alias
  • type_apply
  • type_family
  • type_infix
  • type_instance
  • type_list
  • type_literal
  • type_name
  • type_operator
  • type_parens
  • type_role
  • type_star
  • type_tuple
  • type_unboxed_sum
  • type_unboxed_tuple
  • type_variable
  • variable
  • varop
  • via
  • where
  • wildcard

@wenkokke wenkokke marked this pull request as draft January 17, 2024 12:45
@pokey
Copy link
Member

pokey commented Jan 18, 2024

-- RFC: What should `argumentOrParameter` match in the following case?
fst :: (a, b) -> a
fst tup@(x, y) = x
--  ^^^^^^^^^^     <- 1️⃣ the whole pattern
--  ^^^            <- 2️⃣ only the names of whole arguments (may not be given)
--  ^^^  ^  ^      <- 3️⃣ all names in the left-hand side of the function

I would expect x and y to match here. What is the case for the other ones?

@pokey
Copy link
Member

pokey commented Jan 18, 2024

-- RFC: What should "branch" match?
foo = bar
  where
    bar = 1
--   1️⃣ `foo = bar` and `bar = 1`
--   2️⃣ `foo = bar where bar = 1`
--   3️⃣ `foo = bar where bar = 1` and `bar = 1`

what makes any of them a "branch"?

queries/haskell.hs Outdated Show resolved Hide resolved
@wenkokke
Copy link
Author

wenkokke commented Jan 18, 2024

-- RFC: What should `argumentOrParameter` match in the following case?
fst :: (a, b) -> a
fst tup@(x, y) = x
--  ^^^^^^^^^^     <- 1️⃣ the whole pattern
--  ^^^            <- 2️⃣ only the names of whole arguments (may not be given)
--  ^^^  ^  ^      <- 3️⃣ all names in the left-hand side of the function

I would expect x and y to match here. What is the case for the other ones?

  • tup is the name of the first argument
  • the whole pattern is the structure of the whole first argument
  • x and y aren't the arguments to the function, but the first and second fields of the tuple
tup = (1, 2)

assert (fst tup == 1)

@wenkokke
Copy link
Author

wenkokke commented Jan 18, 2024

-- RFC: What should "branch" match?
foo = bar
  where
    bar = 1
--   1️⃣ `foo = bar` and `bar = 1`
--   2️⃣ `foo = bar where bar = 1`
--   3️⃣ `foo = bar where bar = 1` and `bar = 1`

what makes any of them a "branch"?

all top-level defintions are branches, and it'd be odd to exclude single-branch branching constructs, e.g., having "branch" not match the branch in an if statement without an else

not :: Bool -> Bool
not True = False
not False = True

that's equivalent to

not :: Bool -> Bool
not x = case x of
  True -> False
  False -> True

and equivalent to

not :: Bool -> Bool
not x = if x the False else True

queries/haskell.md Outdated Show resolved Hide resolved
(patterns
(
(_) @argumentOrParameter
) @_.iteration
Copy link
Member

@pokey pokey Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing you don't want this to be the iteration scope for functionName, so you probably want

Suggested change
) @_.iteration
) @argumentOrParameter.iteration

the _ is a wildcard that makes it apply to all scopes defined in the pattern

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, so the iteration scopes aren't scoped?

Copy link
Member

@pokey pokey Jan 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that would be nice, but no. not worth the complexity. fwiw we don't recommend defining iteration scope at the same time as scope, because it actually generates one copy of the iteration scope per scope, which we then silently merge. it's fine to do if it's significantly easier, but shouldn't be your first instinct

iteration scopes are not like domain / removal / leading / whatever, because the iteration scope is genuinely a different scope, where as the latter are attributes of the original scope itself

@pokey
Copy link
Member

pokey commented Jan 18, 2024

shall we make a haskell discussion so we can use threading? all the quoting is quickly going to become a headache 😅

Comment on lines +163 to +305
"branch.match": {
description: "A pattern match branch",
scopeType: "branch",
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this introduces a bit of confusion in Python, where a match statement is basically a switch statement with pattern matching

},
"branch.match.iteration": {
description:
"Iteration scope for pattern match branches; should be the entire branch",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what do you mean by "should be the entire branch"?

Comment on lines 12 to 13
1| fib 0 = 0
>---------<
Copy link
Member

@pokey pokey Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense as the domain, but I think the range should be just the arg list itself

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this looks like a formal argument, not an actual argument 🤔

Comment on lines 12 to 13
1| fib 0 = 0
>-<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as above, this looks like a formal arg not an actual arg

Comment on lines 10 to 11
0| abs :: Int -> Int
><
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm interesting to have zero-width arg here 🤔. tho again, if anything that would be formal

Comment on lines 50 to 53
0| abs :: Int -> Int
>-------------
1| abs x
-----<
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one is surprising

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's an odd one. Might be the same issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this looks identical to at least a few of the other 90+ branch.match.iteration test files you have 😅

Copy link
Member

@pokey pokey Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm all for good test coverage, but >100 test cases for a single facet? 😅. I almost get the impression that you used a script to generate test cases and it went a bit out of control

@pokey
Copy link
Member

pokey commented Jan 25, 2024

note: this PR is semi-blocked on tree-sitter/tree-sitter-haskell#111, which causes the parse tree to sometimes be wrong. For example see name.function34. If run individually, it is correct, if run as part of the whole suite, we get the wrong parse tree.

We could try to come up with a workaround if necessary, but for now we're hoping the issue gets fixed soon

@wenkokke
Copy link
Author

wenkokke commented Feb 21, 2024

note: this PR is semi-blocked on tree-sitter/tree-sitter-haskell#111, which causes the parse tree to sometimes be wrong. For example see name.function34. If run individually, it is correct, if run as part of the whole suite, we get the wrong parse tree.

We could try to come up with a workaround if necessary, but for now we're hoping the issue gets fixed soon

@pokey Would you prefer we (1) move on with incorrect tests, (2) add a workaround which reinstantiates the parser between every run, or (3) fork and temporarily patch tree-sitter-haskell?

@wenkokke
Copy link
Author

Note: This PR is currently blocked on the ongoing rewrite of the Haskell grammar (see #120).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants